package fms.controller;

import fms.core.DownRequestFlp;
import fms.core.FLPXmlBuilder;
import fms.core.IFilter;
import fms.core.Msg620Builder;
import fms.dao.CptSendService;
import fms.dao.FLPMsgBuilder;
import fms.model.CptSend;
import fms.msgupcenter.protocols.AcarsProtocol;
import fms.msgupcenter.protocols.uplinkmsg.UplinkMsgProtocol;
import fms.util.ConfUtil;
import fms.util.DateUtil;
import fms.util.ErrorLevel;
import fms.util.SysConstants;
import fms.xml.FlpRequestXML;
import fms.xml.FlpResponseXML;
import fms.webservice.Request;
import fms.webservice.XmlUtil;
import org.apache.log4j.Logger;
import org.dom4j.Document;
import org.dom4j.DocumentException;
import org.dom4j.Element;
import org.dom4j.io.SAXReader;

import java.io.File;
import java.util.*;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

/**
 * 飞行计划请求与回复模块处理流程：
 * 1、接收过滤报文（我们这个系统不需要考虑发送失败的情况，不用处理回执报）；
 * 2、从原始报文中解析飞行计划请求，
 * 3、查询飞行计划组装回复报文；
 * 5、依次发送分组回复的协议串，并保存Acars风温回复报文自由文，用于web监控系统使用；；
 */
//public class FlpController implements Observer {
public class FlpController implements IReceiver{
    private Logger logger = Logger.getLogger(FlpController.class);
    ExecutorService pool = Executors.newFixedThreadPool(10);
    private ISender sender;
    private  DownRequestFlp downRequestFlp;
    private IFilter filter;

    public ISender getSender() {
        return sender;
    }

    public void setSender(ISender sender) {
        this.sender = sender;
    }

    public DownRequestFlp getDownRequestFlp() {
        return downRequestFlp;
    }

    public void setDownRequestFlp(DownRequestFlp downRequestFlp) {
        this.downRequestFlp = downRequestFlp;
    }


    public IFilter getFilter() {
        return filter;
    }

    public void setFilter(IFilter filter) {
        this.filter = filter;
    }
    public FlpController() {

    }
//    public void update(Observable observable, Object arg) {
//        String msg = (String) arg;
//        if (filter.isFilter(msg))
//        {
//            DealFlp dealFlpRequest = new DealFlp(msg,sender,downRequestFlp);
//            pool.execute(dealFlpRequest);
//        }else{
//            return;
//        }
//    }

    public void receiveMsg(Object arg){
        String msg = (String) arg;
        if (filter.isFilter(msg))
        {
            DealFlp dealFlpRequest = new DealFlp(msg,sender,downRequestFlp);
            pool.execute(dealFlpRequest);
        }else{
            return;
        }

    }

    private static class DealFlp implements Runnable {
        private Logger logger = Logger.getLogger(DealFlp.class);
        private String msg;
        private ISender sender;
        private  DownRequestFlp downRequestFlp;
        private  String replySMI;
        private String uplinkformat;
        private String uplinkreceiver;
        private String uplinksender;
        private String snavailable;

        public void dealFlp( String aContent,DownRequestFlp downRequestFlp)  {
            logger.debug("报文格式符合要求，进行飞行计划解析处理!");
            try {
                Request request = downRequestFlp.parse(aContent);
                if (null == request) {
                    throw new Exception("飞行计划请求解析失败！");
                }

                FlpRequestXML flpRequestXML = XmlUtil.unMarshallFlpRequest(request.getRequestXML());
                CptSendService cptSendService = ConfUtil.getSingletonApplicationContextDao().getBean("cptSendService", CptSendService.class);


                String curUTCTime = DateUtil.getCurUTCtime(SysConstants.FORMAT_DATETIME_FULL);
                String flyPlanValidTime = DateUtil.changeDay(curUTCTime, -2, SysConstants.FORMAT_DATETIME_FULL);

                List<CptSend> cptSendlist =cptSendService.findCptSend(flpRequestXML.getFlightID(), flpRequestXML.getAircraftid(), flyPlanValidTime) ;
                //在数据库中找到原有记录
                if(cptSendlist!=null&&cptSendlist.size()>0){
                    CptSend cptSend=cptSendlist.get(0);
                    String freeTextOfUpMsg=FLPMsgBuilder.build(cptSend);
                    FlpResponseXML flpResponseXML=new FlpResponseXML();
                    flpResponseXML.setResultcode(ErrorLevel.Success);
                    flpResponseXML.setRoutline(freeTextOfUpMsg);
                    flpResponseXML.setFlightID(flpRequestXML.getFlightID());
                    flpResponseXML.setAircraftid(flpRequestXML.getAircraftid());
                    buildSendContent(flpRequestXML, flpResponseXML, cptSend,freeTextOfUpMsg,"1");
                }
                else{
                    logger.info("飞行计划请求未找到记录：航班号 "+flpRequestXML.getFlightID()+", 机尾号："+ flpRequestXML.getAircraftid() +", 飞行计划有效时间："+flyPlanValidTime);
                }
            } catch (Exception e) {
                logger.error("飞行计划请求失败：" + e.getMessage());
                return;
            }

        }
        public void  buildSendContent(FlpRequestXML flpRequestXML,FlpResponseXML flpResponseXML,CptSend cptSend, String freeTextOfUpMsg,String sendStatus){
            logger.debug("飞行计划请求完成，响应信息为：" + "\r\n" + XmlUtil.marshallFlpResponse(flpResponseXML) + "\r\n" + "开始构造上传报文!");
            if (null != flpResponseXML && ErrorLevel.Success.equals(flpResponseXML.getResultcode())) {
                try {
                    String freeAllOutUPMsg ="";
                    String appUpMsgId ="";
                    String masNum="";
                    if(uplinkformat.equals("xml")){
                        freeAllOutUPMsg=FLPXmlBuilder.build(flpRequestXML.getFlightID(), flpRequestXML.getAircraftid(), freeTextOfUpMsg, replySMI);
                        UplinkMsgProtocol protocol = (UplinkMsgProtocol) AcarsProtocol.Deserialize(
                                freeAllOutUPMsg, UplinkMsgProtocol.class);
                        appUpMsgId=protocol.body.uplinkMessage.getHead().getAppUpMsgId();
                        freeAllOutUPMsg=freeAllOutUPMsg.replace("                <appUpMsgId>"+appUpMsgId+"</appUpMsgId>\n","");

                    }
                    else{

                        freeAllOutUPMsg= Msg620Builder.build( flpRequestXML.getAircraftid(), freeTextOfUpMsg, replySMI.substring(0,3), uplinksender, uplinkreceiver,snavailable);
                        int indexMA=freeAllOutUPMsg.indexOf("/MA");
                        masNum=freeAllOutUPMsg.substring(indexMA+4,indexMA+8);
                        int indexSN=freeAllOutUPMsg.indexOf("/SN");
                        if(indexSN!=-1){
                            appUpMsgId=freeAllOutUPMsg.substring(indexSN+3,indexSN+13);
                        }
                    }
                    sender.send(freeAllOutUPMsg);
                    CptSendService cptSendService = ConfUtil.getSingletonApplicationContextDao().getBean("cptSendService", CptSendService.class);
                    cptSend.setSendStatus(sendStatus);
                    cptSend.setSendContent(freeTextOfUpMsg);
                    cptSend.setMasNum(masNum);
                    cptSend.setAppUpMsgId(appUpMsgId);
                    cptSend.setSendDate(DateUtil.getUTCTime());
                    cptSend.setCaptainStatus("0");
                    cptSendService.saveOrUpdate(cptSend);

                } catch (Exception ex) {
                    logger.error("飞行计划错误：", ex);
                    return;
                }
            } else {
                logger.error("风温请求失败，没有获取到数据，状态代码为：" + flpResponseXML.getResultcode());
                return;
            }
        }


        private DealFlp(String msg, ISender sender,  DownRequestFlp downRequestFlp) {
            logger.debug("构造飞行计划请求处理线程！");
            this.sender=sender;
            this.downRequestFlp=downRequestFlp;
            this.msg = msg;
            File fBaseParam = new File(ConfUtil.props.getProperty("baseParamFilePath"));
            uplinkformat=ConfUtil.props.getProperty("uplinkformat");
            uplinksender=ConfUtil.props.getProperty("uplinksender");
            uplinkreceiver=ConfUtil.props.getProperty("uplinkreceiver");
            snavailable=ConfUtil.props.getProperty("snavailable");
            final SAXReader readerBaseParam = new SAXReader();
            try {
                final Document paraseRulenDoc = readerBaseParam.read(fBaseParam);
                Element uniqueObject = (Element) paraseRulenDoc.selectSingleNode("/baseParamter/coreService/flpController/replySMI");
                this.replySMI = uniqueObject.getText();
            } catch (final DocumentException e) {
                logger.error(e.getMessage());
            }

        }
        @Override
        public void run() {
            dealFlp(msg,downRequestFlp);
        }
    }


}
